<?php


namespace helper;


class Xml
{

  /**
   * 生成xml
   * @param $data
   * @return mixed|\SimpleXMLElement
   */
  static public function data2xml($data)
  {
    $xml = new \SimpleXMLElement('<xml></xml>');
    self::_data_to_xml($xml, $data);
    $xml = $xml->asXML();
    return $xml;
  }

  /**
   * XML转数组
   * @param string $xml XML内容
   * @return array
   */
  static public function xml2data($xml)
  {
    $values = array();
    $index  = array();
    $array  = array();
    $parser = xml_parser_create('utf-8');
    xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
    xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
    xml_parse_into_struct($parser, $xml, $values, $index);
    xml_parser_free($parser);
    $i            = 0;
    $name         = $values[$i]['tag'];
    $array[$name] = isset($values[$i]['attributes']) ? $values[$i]['attributes'] : '';
    $array[$name] = self::_xml_to_data($values, $i);
    return $array;
  }

  /**
   * 数据XML编码
   * @param object $xml XML对象
   * @param mixed $data 数据
   * @param string $item 数字索引时的节点名称
   * @return string
   */
  static public function _data_to_xml($xml, $data, $item = 'item')
  {
    foreach ($data as $key => $value) {
      /* 指定默认的数字key */
      is_numeric($key) && $key = $item;
      /* 添加子元素 */
      if (is_array($value) || is_object($value)) {
        $child = $xml->addChild($key);
        self::_data_to_xml($child, $value, $item);
      } else {
        if (is_numeric($value)) {
          $child = $xml->addChild($key, $value);
        } else {
          $child = $xml->addChild($key);
          $node  = dom_import_simplexml($child);
          $cdata = $node->ownerDocument->createCDATASection($value);
          $node->appendChild($cdata);
        }
      }
    }
  }

  /**
   * 节点转换
   * @param array $values XML数据
   * @param integer &$i 指针
   * @return array
   */
  static private function _xml_to_data($values, &$i)
  {
    $child = array();
    if (isset($values[$i]['value'])) array_push($child, $values[$i]['value']);
    while ($i++ < count($values)) {
      switch ($values[$i]['type']) {
        case 'cdata':
          array_push($child, $values[$i]['value']);
          break;
        case 'complete':
          $name = $values[$i]['tag'];
          if (!empty($name)) {
            $child[$name] = ($values[$i]['value']) ? ($values[$i]['value']) : '';
            if (isset($values[$i]['attributes'])) {
              $child[$name] = $values[$i]['attributes'];
            }
          }
          break;
        case 'open':
          $name                = $values[$i]['tag'];
          $size                = isset($child[$name]) ? sizeof($child[$name]) : 0;
          $child[$name][$size] = self::_xml_to_data($values, $i);
          break;
        case 'close':
          return $child;
          break;
      }
    }
    return $child;
  }
}